#include "GlBuffer.h"
#include <glad/gl.h>

namespace lazy {
    GLVertexBuffer::GLVertexBuffer(uint32_t size) {
        glGenBuffers(1, &m_BufferID);
        glBindBuffer(GL_ARRAY_BUFFER, m_BufferID);
        glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
    }

    GLVertexBuffer::GLVertexBuffer(float *vertices, uint32_t size) {
        glGenBuffers(1, &m_BufferID);
        glBindBuffer(GL_ARRAY_BUFFER, m_BufferID);
        glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
    }

    GLVertexBuffer::~GLVertexBuffer() {
        glDeleteBuffers(1, &m_BufferID);
    }

    void GLVertexBuffer::Bind() {
        glBindBuffer(GL_ARRAY_BUFFER, m_BufferID);
    }

    void GLVertexBuffer::Unbind() {
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

    const BufferLayout &GLVertexBuffer::GetLayout() const {
        return m_Layout;
    }

    void GLVertexBuffer::SetLayout(const BufferLayout &layout) {
        m_Layout = layout;
    }

    void GLVertexBuffer::SetData(const void *data, uint32_t size) {
        glBindBuffer(GL_ARRAY_BUFFER, m_BufferID);
        glBufferSubData(GL_ARRAY_BUFFER, 0, size, data);
    }

    GLIndexBuffer::GLIndexBuffer(uint32_t *indices, uint32_t count)
            : m_Count(count) {
        glGenBuffers(1, &m_BufferID);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_BufferID);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW);
    }

    GLIndexBuffer::~GLIndexBuffer() {
        glDeleteBuffers(1, &m_BufferID);
    }

    void GLIndexBuffer::Bind() {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_BufferID);
    }

    void GLIndexBuffer::Unbind() {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    }

    GLUniformBuffer::GLUniformBuffer(uint32_t size, uint32_t binding) {
        glCreateBuffers(1, &m_BufferID);
        glNamedBufferData(m_BufferID, size, nullptr, GL_DYNAMIC_DRAW); // TODO: investigate usage hint
        glBindBufferBase(GL_UNIFORM_BUFFER, binding, m_BufferID);
    }

    GLUniformBuffer::~GLUniformBuffer() {
        glDeleteBuffers(1, &m_BufferID);
    }

    void GLUniformBuffer::SetData(const void *data, uint32_t size, uint32_t offset) {
        glNamedBufferSubData(m_BufferID, offset, size, data);
    }

} // lazy